Ota käyttöön Pythonin operator-moduulin teho kirjoittaaksesi tiiviimpää, tehokkaampaa ja funktionaalisempaa koodia. Löydä sen apuohjelmat yleisiin toimintoihin.
Pythonin operatorimoduuli: Tehokkaita apuohjelmia funktionaaliseen ohjelmointiin
Ohjelmoinnin maailmassa, erityisesti kun omaksutaan funktionaalisen ohjelmoinnin paradigmoja, kyky ilmaista operaatioita puhtaalla, tiiviillä ja uudelleenkäytettävällä tavalla on ensiarvoisen tärkeää. Python, vaikka onkin ensisijaisesti olio-ohjelmointikieli, tarjoaa vankan tuen funktionaalisille ohjelmointityyleille. Tämän tuen keskeinen, joskin joskus unohdettu, komponentti on operator
-moduuli. Tämä moduuli tarjoaa kokoelman tehokkaita funktioita, jotka vastaavat Pythonin sisäisiä operaattoreita, toimien erinomaisina vaihtoehtoina lambda-funktioille ja parantaen koodin luettavuutta ja suorituskykyä.
operator
-moduulin ymmärtäminen
operator
-moduuli määrittelee funktioita, jotka suorittavat Pythonin sisäänrakennettuja operaattoreita vastaavia toimintoja. Esimerkiksi operator.add(a, b)
vastaa a + b
:tä, ja operator.lt(a, b)
vastaa a < b
:tä. Nämä funktiot ovat usein tehokkaampia kuin niitä vastaavat operaattorit, erityisesti suorituskyvyn kannalta kriittisissä yhteyksissä, ja niillä on ratkaiseva rooli funktionaalisissa ohjelmointirakenteissa, kuten map()
, filter()
ja functools.reduce()
.
Miksi käyttäisit funktiota operator
-moduulista suoraan operaattorin sijaan? Ensisijaiset syyt ovat:
- Yhteensopivuus funktionaalisen tyylin kanssa: Monet korkeamman asteen funktiot Pythonissa (kuten ne
functools
-moduulissa) odottavat kutsuttavia objekteja. Operator-funktiot ovat kutsuttavia, mikä tekee niistä täydellisiä argumenttien välittämiseen ilman tarvetta määritellä erillistä lambda-funktiota. - Luettavuus: Tietyissä monimutkaisissa skenaarioissa nimettyjen operator-funktioiden käyttö voi joskus parantaa koodin selkeyttä monimutkaisten lambda-lausekkeiden sijaan.
- Suorituskyky: Tietyissä toiminnoissa, erityisesti kun niitä kutsutaan toistuvasti silmukoiden tai korkeamman asteen funktioiden sisällä, operator-funktiot voivat tarjota pienen suorituskyvyn edun niiden C-toteutuksen ansiosta.
Ydinkäyttöoperator-funktiot
operator
-moduuli voidaan jakaa laajasti niiden edustamien toimintojen tyyppien mukaan. Tarkastellaanpa joitakin yleisimmin käytettyjä.
Aritmeettiset operaattorit
Nämä funktiot suorittavat standardeja aritmeettisia laskutoimituksia. Ne ovat erityisen hyödyllisiä, kun sinun on välitettävä aritmeettinen operaatio argumenttina toiselle funktiolle.
operator.add(a, b)
: Vastaaa + b
:tä.operator.sub(a, b)
: Vastaaa - b
:tä.operator.mul(a, b)
: Vastaaa * b
:tä.operator.truediv(a, b)
: Vastaaa / b
:tä (tosi jako).operator.floordiv(a, b)
: Vastaaa // b
:tä (kokonaislukujaon alaspäin pyöristys).operator.mod(a, b)
: Vastaaa % b
:tä (modulo).operator.pow(a, b)
: Vastaaa ** b
:tä (potenssiin korotus).operator.neg(a)
: Vastaa-a
:ta (unaarinen negaatio).operator.pos(a)
: Vastaa+a
:ta (unaarinen positiivi).operator.abs(a)
: Vastaaabs(a)
:ta.
Esimerkki: operator.add
:n käyttö functools.reduce
:n kanssa
Kuvittele, että sinun on laskettava kaikkien luettelon elementtien summa. Vaikka sum()
on Pythonin mukaisin tapa, reduce
:n käyttö operator-funktion kanssa osoittaa sen hyödyllisyyden:
import operator
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# Using reduce with operator.add
total = reduce(operator.add, numbers)
print(f"The sum of {numbers} is: {total}") # Output: The sum of [1, 2, 3, 4, 5] is: 15
Tämä vastaa toiminnallisesti seuraavaa:
total_lambda = reduce(lambda x, y: x + y, numbers)
print(f"Sum using lambda: {total_lambda}") # Output: Sum using lambda: 15
The operator.add
-versio on usein suositumpi sen selkeyden ja potentiaalisten suorituskykyetujen vuoksi.
Vertailuoperaattorit
Nämä funktiot suorittavat vertailuja kahden operandin välillä.
operator.lt(a, b)
: Vastaaa < b
:tä (pienempi kuin).operator.le(a, b)
: Vastaaa <= b
:tä (pienempi tai yhtä suuri kuin).operator.eq(a, b)
: Vastaaa == b
:tä (yhtä suuri kuin).operator.ne(a, b)
: Vastaaa != b
:tä (ei yhtä suuri kuin).operator.ge(a, b)
: Vastaaa >= b
:tä (suurempi tai yhtä suuri kuin).operator.gt(a, b)
: Vastaaa > b
:tä (suurempi kuin).
Esimerkki: Sanakirjojen luettelon lajittelu tietyn avaimen perusteella
Oletetaan, että sinulla on luettelo käyttäjäprofiileista, joista jokainen on esitetty sanakirjana, ja haluat lajitella ne 'score'-avaimen perusteella.
import operator
users = [
{'name': 'Alice', 'score': 85},
{'name': 'Bob', 'score': 92},
{'name': 'Charlie', 'score': 78}
]
# Sort users by score using operator.itemgetter
sorted_users = sorted(users, key=operator.itemgetter('score'))
print("Users sorted by score:")
for user in sorted_users:
print(user)
# Output:
# Users sorted by score:
# {'name': 'Charlie', 'score': 78}
# {'name': 'Alice', 'score': 85}
# {'name': 'Bob', 'score': 92}
Tässä operator.itemgetter('score')
on kutsuttava objekti, joka, kun sille annetaan sanakirja, palauttaa 'score'-avaimeen liittyvän arvon. Tämä on puhtaampaa ja tehokkaampaa kuin kirjoittaa key=lambda user: user['score']
.
Boolen operaattorit
Nämä funktiot suorittavat loogisia operaatioita.
operator.not_(a)
: Vastaanot a
:ta.operator.truth(a)
: PalauttaaTrue
, josa
on tosi, muutenFalse
.operator.is_(a, b)
: Vastaaa is b
:tä.operator.is_not(a, b)
: Vastaaa is not b
:tä.
Esimerkki: Epätosien arvojen suodattaminen pois
Voit käyttää operator.truth
-funktiota filter()
-funktion kanssa poistaaksesi kaikki epätodet arvot (kuten 0
, None
, tyhjät merkkijonot, tyhjät listat) iterointikohdasta.
import operator
data = [1, 0, 'hello', '', None, [1, 2], []]
# Filter out falsy values using operator.truth
filtered_data = list(filter(operator.truth, data))
print(f"Original data: {data}")
print(f"Filtered data (truthy values): {filtered_data}")
# Output:
# Original data: [1, 0, 'hello', '', None, [1, 2], []]
# Filtered data (truthy values): [1, 'hello', [1, 2]]
Bittioperaattorit
Nämä funktiot käsittelevät kokonaislukujen yksittäisiä bittejä.
operator.and_(a, b)
: Vastaaa & b
:tä.operator.or_(a, b)
: Vastaaa | b
:tä.operator.xor(a, b)
: Vastaaa ^ b
:tä.operator.lshift(a, b)
: Vastaaa << b
:tä.operator.rshift(a, b)
: Vastaaa >> b
:tä.operator.invert(a)
: Vastaa~a
:ta.
Esimerkki: Bittioperaatioiden suorittaminen
import operator
a = 10 # Binary: 1010
b = 4 # Binary: 0100
print(f"a & b: {operator.and_(a, b)}") # Output: a & b: 0 (Binary: 0000)
print(f"a | b: {operator.or_(a, b)}") # Output: a | b: 14 (Binary: 1110)
print(f"a ^ b: {operator.xor(a, b)}") # Output: a ^ b: 14 (Binary: 1110)
print(f"~a: {operator.invert(a)}") # Output: ~a: -11
Jono- ja kuvausoperaattorit
Nämä funktiot ovat hyödyllisiä elementtien käsittelyyn jonoissa (kuten listoissa, monikoissa, merkkijonoissa) ja kuvauksissa (kuten sanakirjoissa).
operator.getitem(obj, key)
: Vastaaobj[key]
:tä.operator.setitem(obj, key, value)
: Vastaaobj[key] = value
:a.operator.delitem(obj, key)
: Vastaadel obj[key]
:tä.operator.len(obj)
: Vastaalen(obj)
:tä.operator.concat(a, b)
: Vastaaa + b
:tä (jonoille kuten merkkijonoille tai listoille).operator.contains(obj, item)
: Vastaaitem in obj
:tä.
operator.itemgetter
: Tehokas työkalu
Kuten lajitteluesimerkissä vihjattiin, operator.itemgetter
on erikoistunut funktio, joka on uskomattoman hyödyllinen. Kun sitä kutsutaan yhdellä tai useammalla argumentilla, se palauttaa kutsuttavan objektin, joka hakee kyseiset kohteet operandistaan. Jos useita argumentteja annetaan, se palauttaa haettujen kohteiden monikon.
import operator
# Fetching a single item
get_first_element = operator.itemgetter(0)
my_list = [10, 20, 30]
print(f"First element: {get_first_element(my_list)}") # Output: First element: 10
# Fetching multiple items
get_first_two = operator.itemgetter(0, 1)
print(f"First two elements: {get_first_two(my_list)}") # Output: First two elements: (10, 20)
# Fetching items from a dictionary
get_name_and_score = operator.itemgetter('name', 'score')
user_data = {'name': 'Alice', 'score': 85, 'city': 'New York'}
print(f"User info: {get_name_and_score(user_data)}") # Output: User info: ('Alice', 85)
operator.itemgetter
on myös erittäin tehokas, kun sitä käytetään key
-argumenttina lajittelussa tai muissa funktioissa, jotka hyväksyvät avainfunktion.
operator.attrgetter
: Attribuuttien käsittely
Samanlainen kuin itemgetter
, operator.attrgetter
palauttaa kutsuttavan objektin, joka hakee attribuutteja operandistaan. Se on erityisen kätevä työskenneltäessä objektien kanssa.
import operator
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
products = [
Product('Laptop', 1200),
Product('Mouse', 25),
Product('Keyboard', 75)
]
# Get all product names
get_name = operator.attrgetter('name')
product_names = [get_name(p) for p in products]
print(f"Product names: {product_names}") # Output: Product names: ['Laptop', 'Mouse', 'Keyboard']
# Sort products by price
sorted_products = sorted(products, key=operator.attrgetter('price'))
print("Products sorted by price:")
for p in sorted_products:
print(f"- {p.name}: ${p.price}")
# Output:
# Products sorted by price:
# - Mouse: $25
# - Keyboard: $75
# - Laptop: $1200
attrgetter
voi myös käyttää attribuutteja sisäkkäisten objektien kautta pistenotaatiota käyttäen. Esimerkiksi operator.attrgetter('address.city')
hakisi 'city'-attribuutin objektin 'address'-attribuutista.
Muita hyödyllisiä funktioita
operator.methodcaller(name, *args, **kwargs)
: Palauttaa kutsuttavan objektin, joka kutsuu nimeltäänname
olevaa metodia operandillaan. Tämä on metodin vastineitemgetter
:lle jaattrgetter
:lle.
Esimerkki: Metodin kutsuminen luettelon objekteilla
import operator
class Greeter:
def __init__(self, name):
self.name = name
def greet(self, message):
return f"{self.name} says: {message}"
greeters = [Greeter('Alice'), Greeter('Bob')]
# Call the greet method on each Greeter object
call_greet = operator.methodcaller('greet', 'Hello from the operator module!')
greetings = [call_greet(g) for g in greeters]
print(greetings)
# Output: ['Alice says: Hello from the operator module!', 'Bob says: Hello from the operator module!']
operator
-moduuli funktionaalisissa ohjelmointikonteksteissa
operator
-moduulin todellinen teho tulee esiin, kun sitä käytetään yhdessä Pythonin sisäänrakennettujen funktionaalisen ohjelmoinnin työkalujen, kuten map()
, filter()
ja functools.reduce()
, kanssa.
map()
ja operator
map(function, iterable, ...)` soveltaa funktiota jokaiseen iterointikohteen alkioon ja palauttaa iteraattorin tuloksista. Operator-funktiot ovat tähän täydellisiä.
import operator
numbers = [1, 2, 3, 4, 5]
# Square each number using map and operator.mul
squared_numbers = list(map(lambda x: operator.mul(x, x), numbers)) # Can be simpler: list(map(operator.mul, numbers, numbers)) or list(map(pow, numbers, [2]*len(numbers)))
print(f"Squared numbers: {squared_numbers}") # Output: Squared numbers: [1, 4, 9, 16, 25]
# Add 10 to each number using map and operator.add
added_ten = list(map(operator.add, numbers, [10]*len(numbers)))
print(f"Numbers plus 10: {added_ten}") # Output: Numbers plus 10: [11, 12, 13, 14, 15]
filter()
ja operator
filter(function, iterable)` muodostaa iteraattorin iterointikohteen elementeistä, joille funktio palauttaa toden. Olemme nähneet
operator.truth
-funktion, mutta muut vertailuoperaattorit ovat myös erittäin hyödyllisiä.
import operator
salaries = [50000, 65000, 45000, 80000, 70000]
# Filter salaries greater than 60000
high_salaries = list(filter(operator.gt, salaries, [60000]*len(salaries)))
print(f"Salaries above 60000: {high_salaries}") # Output: Salaries above 60000: [65000, 80000, 70000]
# Filter even numbers using operator.mod and lambda (or a more complex operator function)
even_numbers = list(filter(lambda x: operator.eq(operator.mod(x, 2), 0), [1, 2, 3, 4, 5, 6]))
print(f"Even numbers: {even_numbers}") # Output: Even numbers: [2, 4, 6]
functools.reduce()
ja operator
functools.reduce(function, iterable[, initializer])` soveltaa kahden argumentin funktiota kumulatiivisesti iterointikohteen alkioihin vasemmalta oikealle, jotta iterointikohde supistetaan yhdeksi arvoksi. Operator-funktiot ovat ihanteellisia binääritoiminnoille.
import operator
from functools import reduce
numbers = [2, 3, 4, 5]
# Calculate the product of numbers
product = reduce(operator.mul, numbers)
print(f"Product: {product}") # Output: Product: 120
# Find the maximum number
maximum = reduce(operator.gt, numbers)
print(f"Maximum: {maximum}") # This doesn't work as expected for max, need to use a lambda or custom function for max:
# Using lambda for max:
maximum_lambda = reduce(lambda x, y: x if x > y else y, numbers)
print(f"Maximum (lambda): {maximum_lambda}") # Output: Maximum (lambda): 5
# Note: The max() built-in function is generally preferred for finding the maximum.
Suorituskykyyn liittyviä näkökohtia
Vaikka suorituskykyerot voivat olla merkityksettömiä monissa arkipäivän skripteissä, operator
-moduulin funktiot on toteutettu C:llä ja ne voivat tarjota nopeusetua vastaavaan Python-koodiin (erityisesti lambda-funktioihin) verrattuna, kun niitä käytetään tiukoissa silmukoissa tai käsiteltäessä erittäin suuria tietojoukkoja. Tämä johtuu siitä, että ne välttävät Pythonin funktionkutsun mekanismiin liittyvän yleiskustannuksen.
Esimerkiksi käytettäessä operator.itemgetter
:iä tai operator.attrgetter
:iä avaimina lajittelussa, ne ovat yleensä nopeampia kuin vastaavat lambda-funktiot. Vastaavasti aritmeettisissa operaatioissa map
- tai reduce
-funktion sisällä, operator-funktiot voivat tarjota pienen lisäyksen nopeudessa.
Milloin käyttää operator
-moduulin funktioita
Tässä on pikaopas, milloin operator
-moduuliin kannattaa tarttua:
- Argumentteina korkeamman asteen funktioille: Kun funktioita välitetään
map
:ille,filter
:ille,sorted
:ille,functools.reduce
:lle tai vastaaville rakenteille. - Kun luettavuus paranee: Jos operator-funktio tekee koodistasi selkeämmän kuin lambda, käytä sitä.
- Suorituskykykriittisessä koodissa: Jos profiloit koodiasi ja huomaat, että operaattorikutsut ovat pullonkaula, moduulin funktiot voivat auttaa.
- Kohteiden/attribuuttien käsittelyyn:
operator.itemgetter
jaoperator.attrgetter
ovat lähes aina suositeltavampia kuin lambdat tähän tarkoitukseen niiden selkeyden ja tehokkuuden vuoksi.
Yleisiä sudenkuoppia ja parhaita käytäntöjä
- Älä käytä liikaa: Jos yksinkertainen operaattori kuten
+
tai*
on riittävän selkeä kontekstissaan, pysy siinä.operator
-moduuli on tarkoitettu funktionaalisten ohjelmointityylien parantamiseen tai kun eksplisiittisiä funktioargumentteja tarvitaan. - Ymmärrä palautusarvot: Muista, että funktiot kuten
map
jafilter
palauttavat iteraattoreita. Jos tarvitset luettelon, muunna tulos eksplisiittisesti käyttämällälist()
-funktiota. - Yhdistä muihin työkaluihin:
operator
-moduuli on tehokkaimmillaan, kun sitä käytetään yhdessä muiden Python-rakenteiden ja moduulien, erityisestifunctools
:in, kanssa. - Luettavuus ensin: Vaikka suorituskyky onkin tekijä, priorisoi selkeä ja ylläpidettävä koodi. Jos lambda on välittömästi ymmärrettävämpi tietyssä, yksinkertaisessa tapauksessa, se voi olla hyväksyttävä.
Johtopäätös
Pythonin operator
-moduuli on arvokas, joskin joskus aliarvostettu, työkalu jokaisen Python-ohjelmoijan työkalupakissa, erityisesti niille, jotka suosivat funktionaalista ohjelmointia. Tarjoamalla suoria, tehokkaita ja kutsuttavia vastaavuuksia Pythonin operaattoreille se virtaviivaistaa elegantin ja suorituskykyisen koodin luomista. Lajitteletpa sitten monimutkaisia tietorakenteita, suoritatko aggregointioperaatioita tai sovellatko muunnoksia, operator
-moduulin funktioiden hyödyntäminen voi johtaa tiiviimpiin, luettavampiin ja optimoidumpiin Python-ohjelmiin. Ota nämä apuohjelmat käyttöön parantaaksesi Python-koodauskäytäntöjäsi.